package com.atguigu.utils;

import org.apache.poi.ss.formula.functions.T;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * @author zhengkaiyuan
 * @version 1.0
 * @create 2021-06-23 16:32
 */

//用于下载当前页面的文件(excel文件)
public class DownLoadUtils {
    /**
     * @param fileName  用于创建的excel文件的名称
     * @param data      放入excel当中的数据
     * @param filePath   存放的路径
     * @param originTitle  表头信息(数据库字段的类元信息)
     */
    public static void createExcel(String fileName,List<Map<String,String>> data, String filePath,String[] originTitle) throws IOException {
        //在内存中创建一个Excel文件
        XSSFWorkbook workbook = new XSSFWorkbook();
        //创建工作表，指定工作表名称
        XSSFSheet sheet = workbook.createSheet(fileName);
        //创建行，0表示第一行
        XSSFRow row = sheet.createRow(0);
        //第一行初始化表头信息
        for (int i = 0; i < originTitle.length; i++) {
            row.createCell(i).setCellValue(originTitle[i]);
        }

        //定义每一行的索引位置(即添加数据的索引位置)
        int index = 1;
        //循环向excel中添加数据
        for (Map<String,String> rowData : data) {
            row = sheet.createRow(index++);
            fillerDate(row,rowData,originTitle);
        }
        //拼接地址
        String address = filePath+ File.separator+fileName+".xlsx";
        //通过输出流将workbook对象下载到磁盘
        FileOutputStream out = new FileOutputStream(address);
        workbook.write(out);
        out.flush();//刷新
        out.close();//关闭
        workbook.close();
    }

    /**
     *
     * @param row   为从第二行添加数据的行号
     * @param rowData  为这一行需要添加的数据
     * @param originTitle  获取第一行的表头信息
     */
    private static void fillerDate(XSSFRow row, Map<String, String> rowData, String[] originTitle) {
        for (int i = 0; i < originTitle.length; i++) {
            String value = rowData.get(originTitle[i]);
            row.createCell(i).setCellValue(value);
        }
    }


    /**
     * @param list   需要封装成map的集合
     * @param originTitle   类元信息
     */
    public static  <T> List<Map<String,String>>  wrapMap(List<T> list, String[] originTitle) throws Exception {
        List<Map<String,String>> maps = new ArrayList<>();
        if (list.size() == 0){
            throw new RuntimeException("没有数据，无法下载！");
        }else {
            //获取当前集合中数据的类型
            Class<?> clazz = list.get(0).getClass();
            for (T item : list) {
                Map<String, String> valueMap = new HashMap<>();
                for (String filed : originTitle) {
                    Field field = clazz.getDeclaredField(filed);
                    field.setAccessible(true);
                    Object value = field.get(item);
                    if (value == null) {
                        valueMap.put(filed, "暂无");
                    } else {
                        valueMap.put(filed, value.toString());
                    }
                }
                maps.add(valueMap);
            }
            return maps;
        }
    }





    /*====================================更新=====================================================*/

    /**
     * @param fileName   指定的上传文件名称
     * @param list       指定的上传数据
     * @param filePath   指定的上传文件路径
     * @param <T>
     * @throws Exception
     */
    public static <T> void createExcel(String fileName, List<T> list, String filePath) throws Exception {
        if (list.size() <= 0){
            throw new RuntimeException("不存在数据,无法下载");
        }
        System.out.println("fileName = " + fileName+"开始下载");
        //在内存中创建一个Excel文件
        XSSFWorkbook workbook = new XSSFWorkbook();
        //创建sheet页并添加数据
        creatSheetAndFillerData(workbook,list,fileName);
        //拼接地址 防止文件名称重复
        String address = filePath+ File.separator+fileName+".xlsx";
        //通过输出流将workbook对象下载到磁盘
        FileOutputStream out = new FileOutputStream(address);
        workbook.write(out);
        out.flush();//刷新
        out.close();//关闭
        workbook.close();
    }


    /**
     * 创建sheet页，并为sheet页填充数据
     * @param workbook    当前的excel文件
     * @param list        sheet页当中的数据
     * @param fileName     sheet页的名称
     * @param <T>
     * @throws Exception
     */
    private static <T> void creatSheetAndFillerData(XSSFWorkbook workbook,List<T> list,String fileName)throws Exception{
        //创建工作表，指定工作表名称
        XSSFSheet sheet = workbook.createSheet(fileName);
        //创建行，0表示第一行
        XSSFRow row = sheet.createRow(0);
        //获取类元信息
        //获取当前集合中数据的类型,以及对应的类元信息
        Class<?> instance = list.get(0).getClass();
        List<String> meta =getMeta(instance);
//        第一行初始化表头信息
        for (int i = 0; i < meta.size(); i++) {
            row.createCell(i).setCellValue(meta.get(i));
        }
        //封装数据
        List<Map<String, String>> maps = wrapMap(list);
        //定义每一行的索引位置(即添加数据的索引位置)
        int index = 1;
        //循环向excel中添加数据
        for (Map<String,String> rowData : maps) {
            row = sheet.createRow(index++);
            fillerDate(row,rowData,meta);
        }
    }


    /**
     *
     * @param fileName   指定的上传文件名称
     * @param list       指定的上传数据
     * @param filePath   指定的上传文件路径
     * @param <T>
     * @return            带返回文件名带有下载条数
     * @throws Exception
     */
    public static <T> String createExcelToName(String fileName, List<T> list, String filePath) throws Exception {
        if (list.size() <= 0){
            throw new RuntimeException("不存在数据,无法下载");
        }
        System.out.println("fileName = " + fileName+"开始下载");
        //在内存中创建一个Excel文件
        XSSFWorkbook workbook = new XSSFWorkbook();
        //创建sheet页并添加数据
        creatSheetAndFillerData(workbook,list,fileName);
        //拼接地址 防止文件名称重复
        String realFileName = fileName + "-"+ list.size()+"-item";
        String address = filePath+ File.separator+realFileName+".xlsx";
        //通过输出流将workbook对象下载到磁盘
        FileOutputStream out = new FileOutputStream(address);
        workbook.write(out);
        out.flush();//刷新
        out.close();//关闭
        workbook.close();

        return realFileName+".xlsx";
    }



    /**
     *
     * @param row   为从第二行添加数据的行号
     * @param rowData  为这一行需要添加的数据
     * @param originTitle  获取第一行的表头信息
     */
    private static void fillerDate(XSSFRow row, Map<String, String> rowData, List<String> originTitle) {
        for (int i = 0; i < originTitle.size(); i++) {
            String value = rowData.get(originTitle.get(i));
            row.createCell(i).setCellValue(value);
        }
    }



    /**
     * @param list   需要封装成map的集合
     */
    private static  <T> List<Map<String,String>>  wrapMap(List<T> list) throws Exception {
        List<Map<String,String>> maps = new ArrayList<>();
        if (list.size() == 0){
            throw new RuntimeException("没有数据，无法下载！");
        }else {
            //获取当前集合中数据的类型,以及对应的类元信息
            Class<?> instance = list.get(0).getClass();
            List<String> meta =getMeta(instance);
            for (T item : list) {
                Map<String, String> valueMap = new HashMap<>();
                for (String filed : meta) {
                    Field field = instance.getDeclaredField(filed);
                    field.setAccessible(true);
                    Object value = field.get(item);
                    if (value == null) {
                        valueMap.put(filed, "暂无");
                    } else {
                        valueMap.put(filed, value.toString());
                    }
                }
                maps.add(valueMap);
            }
            return maps;
        }
    }


    /**
     * 获取类元信息
     * @param instance
     * @return
     */
    private static List<String> getMeta(Class<?> instance) {
        //获取当前对象的所有类元信息
        Field[] declaredFields = instance.getDeclaredFields();
        //定义返回数组
        List<String> meta = new ArrayList<>();
        int index = 0;
        //遍历当前字段的名称
        for (Field declaredField : declaredFields) {
            String fieldName = declaredField.getName();
            if (fieldName.contains("img")){
                continue;
            }else {
                meta.add(fieldName);
            }
        }
        return meta;
    }

    /**
     * 判断当前是否为参数化泛型
     * @param declaredField
     * @return
     */
    private static boolean judge(Field declaredField){
        if (declaredField.getGenericType() instanceof ParameterizedType){
            Type genericType = declaredField.getGenericType();
            //ParameterizedType就是参数化类型
            ParameterizedType pt = (ParameterizedType) genericType;
            //getRawType()返回Tpye，得到“<>”前面的类型，比如List<String>
            if (pt.getRawType().equals(List.class)){
                return true;
            }
        }
        return false;
    }
}
